﻿using KAKA.Domain;
using KAKA.Models;
using KAKA.Repository;
using KAKA.Service;
using Morus;
using Morus.Infrastructure;
using MvcContrib;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Mvc;

namespace KAKA.Controllers
{
    [EmailVerification(ExcludeActionName = new string[] { "VerifyEmail", "SendEmailVerificationSuccess", "ActivateEmail" })]
    public class PersonalController : BaseController
    {
        public PersonalController()
            : base()
        {
            MemberRepository = IoC.Resolve<MemberRepository>();
        }

        public IMemberRepository MemberRepository { get; private set; }

        public ActionResult Index()
        {
            return View();
        }

        [Authorization]
        [Authentication]
        public ActionResult Basic(bool? welcome)
        {
            var member = MemberRepository.Get(CurrentUser.Id);
            var model = new BasicModel()
            {
                Gender = member.Gender.ToString(),
                Nickname = member.Nickname,
                FinalBirthday = member.Birthday.HasValue ? member.Birthday.Value.ToString("yyyy-MM-dd") : string.Empty,
                BirthYear = member.Birthday.HasValue ? member.Birthday.Value.Year.ToString() : string.Empty,
                BirthMonth = member.Birthday.HasValue ? member.Birthday.Value.Month.ToString() : string.Empty,
                BirthDay = member.Birthday.HasValue ? member.Birthday.Value.Day.ToString() : string.Empty,
                Marry = member.Marry,
                Child = member.Child,
                Education = member.Education,
                Province = member.Province,
                City = member.City,
                Occupation = member.Occupation,
                Income = member.Income,
                FriendType = member.FriendType,
                Height = member.Height.HasValue ? member.Height.Value.ToString("#") : string.Empty
            };

            ViewBag.MarrySet = DictionaryRepository.FindByType("Marry").ToSelectList(true);
            ViewBag.ChildSet = DictionaryRepository.FindByType("Child").ToSelectList(true);
            ViewBag.EducationSet = DictionaryRepository.FindByType("Education").ToSelectList(true);
            ViewBag.OccupationSet = DictionaryRepository.FindByType("Occupation").ToSelectList(true);
            ViewBag.IncomeSet = DictionaryRepository.FindByType("Income").OrderBy(r => r.Value).ToSelectList(true);
            ViewBag.FriendTypeSet = DictionaryRepository.FindByType("FriendType").ToSelectList(true);
            ViewBag.HeightSet = WebUtil.GetRange(140, 230, 0, true, "请选择");
            ViewBag.BirthYearSet = WebUtil.GetRange(1940, DateTime.Now.AddYears(-18).Year, 1980, false, "请选择");
            ViewBag.BirthMonthSet = WebUtil.GetRange(1, 12, 1, false, "请选择");
            ViewBag.BirthDaySet = WebUtil.GetRange(1, 31, 1, false, "请选择");
            ViewBag.Welcome = welcome;
            ViewBag.User = CurrentUser;

            return View(model);
        }

        [Authorization]
        [Authentication]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Basic(BasicModel model)
        {
            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var member = MemberRepository.Get(CurrentUser.Id);

                    if (CurrentUser.IsAdministrator() && member.Gender == Gender.None)
                    {
                        member.Gender = model.Gender.ToEnum<Gender>();
                    }
                    if (member.Birthday.HasValue == false)
                    {
                        member.Birthday = new DateTime(int.Parse(model.BirthYear), int.Parse(model.BirthMonth), int.Parse(model.BirthDay));
                        member.Age = member.Birthday != null ? (int?)(DateTime.Now.Year - member.Birthday.Value.Year) : null;
                    }
                    member.Marry = model.Marry;
                    member.Child = model.Child;
                    member.Education = model.Education;
                    member.Province = model.Province;
                    member.City = model.City;
                    member.Occupation = model.Occupation;
                    member.Income = model.Income;
                    member.FriendType = model.FriendType;
                    member.Height = model.Height != null ? (decimal?)decimal.Parse(model.Height) : null;

                    uow.Commit();
                }
            }

            return Basic(false);
        }

        [Authorization]
        public ActionResult Management()
        {
            return View();
        }

        [Authorization]
        public ActionResult MailBox()
        {
            return View();
        }

        [Authorization]
        public ActionResult Friend()
        {
            return View();
        }

        [Authorization]
        public ActionResult Detail()
        {
            var member = MemberRepository.Get(CurrentUser.Id);
            var model = new DetailModel()
            {
                RegisteredProvince = member.RegisteredProvince,
                RegisteredCity = member.RegisteredCity,
                Weight = member.Weight.HasValue ? member.Weight.Value.ToString("#") : string.Empty,
                Zodiac = member.Zodiac,
                Blood = member.Blood,
                Asterism = member.Asterism,
                Nation = member.Nation,
                Religion = member.Religion,
                Nationality = member.Nationality,
            };

            ViewBag.ZodiacSet = DictionaryRepository.FindByType("Zodiac").ToSelectList(true);
            ViewBag.BloodSet = DictionaryRepository.FindByType("Blood").ToSelectList(true);
            ViewBag.AsterismSet = DictionaryRepository.FindByType("Asterism").ToSelectList(true);
            ViewBag.NationSet = DictionaryRepository.FindByType("Nation").ToSelectList(true);
            ViewBag.ReligionSet = DictionaryRepository.FindByType("Religion").ToSelectList(true);
            ViewBag.NationalitySet = DictionaryRepository.FindByType("Nationality").ToSelectList(true);

            return View(model);
        }

        [Authorization]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Detail(DetailModel model)
        {
            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var member = MemberRepository.Get(CurrentUser.Id);

                    member.RegisteredProvince = model.RegisteredProvince;
                    member.RegisteredCity = model.RegisteredCity;
                    member.Weight = model.Weight != null ? (decimal?)decimal.Parse(model.Weight) : null;
                    member.Zodiac = model.Zodiac;
                    member.Blood = model.Blood;
                    member.Asterism = model.Asterism;
                    member.Nation = model.Nation;
                    member.Religion = model.Religion;
                    member.Nationality = model.Nationality;

                    uow.Commit();
                }
            }

            return Detail();
        }

        [Authorization]
        public ActionResult Family()
        {
            var member = MemberRepository.Get(CurrentUser.Id);
            var model = new FamilyModel()
            {
                Monotropic = member.Monotropic,
                Dink = member.Dink,
                Singleton = member.Singleton,
                Living = member.Living,
                Car = member.Car,
                House = member.House,
            };

            ViewBag.MonotropicSet = DictionaryRepository.FindByType("Monotropic").ToSelectList(true);
            ViewBag.DinkSet = DictionaryRepository.FindByType("Dink").ToSelectList(true);
            ViewBag.SingletonSet = DictionaryRepository.FindByType("Singleton").ToSelectList(true);
            ViewBag.LivingSet = DictionaryRepository.FindByType("Living").ToSelectList(true);
            ViewBag.CarSet = DictionaryRepository.FindByType("Car").ToSelectList(true);
            ViewBag.HouseSet = DictionaryRepository.FindByType("House").ToSelectList(true);

            return View(model);
        }

        [Authorization]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Family(FamilyModel model)
        {
            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var member = MemberRepository.Get(CurrentUser.Id);

                    member.Monotropic = model.Monotropic;
                    member.Dink = model.Dink;
                    member.Singleton = model.Singleton;
                    member.Living = model.Living;
                    member.Car = model.Car;
                    member.House = model.House;

                    uow.Commit();
                }
            }

            return Family();
        }

        [Authorization]
        public ActionResult Habit()
        {
            var member = MemberRepository.Get(CurrentUser.Id);
            var model = new HabitModel()
            {
                Health = member.Health,
                Smoke = member.Smoke,
                Drink = member.Drink,
                Life = member.Life,
                Exercise = member.Exercise,
            };

            ViewBag.HealthSet = DictionaryRepository.FindByType("Health").ToSelectList(true);
            ViewBag.SmokeSet = DictionaryRepository.FindByType("Smoke").ToSelectList(true);
            ViewBag.DrinkSet = DictionaryRepository.FindByType("Drink").ToSelectList(true);
            ViewBag.LifeSet = DictionaryRepository.FindByType("Life").ToSelectList(true);
            ViewBag.ExerciseSet = DictionaryRepository.FindByType("Exercise").ToSelectList(true);

            return View(model);
        }

        [Authorization]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Habit(HabitModel model)
        {
            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var member = MemberRepository.Get(CurrentUser.Id);

                    member.Health = model.Health;
                    member.Smoke = model.Smoke;
                    member.Drink = model.Drink;
                    member.Life = model.Life;
                    member.Exercise = model.Exercise;

                    uow.Commit();
                }
            }

            return Habit();
        }

        [Authorization]
        public ActionResult Work()
        {
            var member = MemberRepository.Get(CurrentUser.Id);
            var model = new WorkModel()
            {
                Trade = member.Trade,
                TradeType = member.TradeType,
                WorkState = member.WorkState,
                IncomeDetail = member.IncomeDetail,
                Company = member.Company,
                Department = member.Department,
                Duty = member.Duty,
                Investment = member.Investment,
                School = member.School,
                Major = member.Major,
            };

            ViewBag.TradeSet = DictionaryRepository.FindByType("Trade").ToSelectList(true);
            ViewBag.TradeTypeSet = DictionaryRepository.FindByType("TradeType").ToSelectList(true);
            ViewBag.WorkStateSet = DictionaryRepository.FindByType("WorkState").ToSelectList(true);
            ViewBag.IncomeDetailSet = DictionaryRepository.FindByType("IncomeDetail").ToSelectList(true);
            ViewBag.MajorSet = DictionaryRepository.FindByType("Major").ToSelectList(true);

            return View(model);
        }

        [Authorization]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Work(WorkModel model)
        {
            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var member = MemberRepository.Get(CurrentUser.Id);

                    member.Trade = model.Trade;
                    member.TradeType = model.TradeType;
                    member.WorkState = model.WorkState;
                    member.IncomeDetail = model.IncomeDetail;
                    member.Company = model.Company;
                    member.Department = model.Department;
                    member.Duty = model.Duty;
                    member.Investment = model.Investment;
                    member.School = model.School;
                    member.Major = model.Major;

                    uow.Commit();
                }
            }

            return Work();
        }

        [Authorization]
        [Authentication]
        public ActionResult Declaration()
        {
            var member = MemberRepository.Get(CurrentUser.Id);
            var model = new DeclarationModel
            {
                Declaration = member.Declaration.Content,
            };

            return View(model);
        }

        [Authorization]
        [Authentication]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Declaration(DeclarationModel model)
        {
            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var member = MemberRepository.Get(CurrentUser.Id);

                    member.Declaration.Content = model.Declaration;

                    uow.Commit();
                }
            }
            return Declaration();
        }

        [Authorization]
        [Authentication]
        public ActionResult Portrait()
        {
            var member = MemberRepository.Get(CurrentUser.Id);
            var model = new PortraitModel()
            {
                Portrait = member.Portrait,
                Id = member.Id.Shrink()
            };
            ViewBag.CurrentId = CurrentUser.Id.Shrink();

            return View(model);
        }

        [Authorization]
        [Authentication]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult UploadPortrait(PortraitModel model)
        {
            if (model.ImageTemp.IsNotEmpty())
            {
                var x1 = (int)Convert.ToDecimal(model.ImageX1);
                var y1 = (int)Convert.ToDecimal(model.ImageY1);
                var x2 = (int)Convert.ToDecimal(model.ImageX2);
                var y2 = (int)Convert.ToDecimal(model.ImageY2);
                var w = (int)Convert.ToDecimal(model.ImageWidth);
                var h = (int)Convert.ToDecimal(model.ImageHeight);

                var extension = ".jpg";
                var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "temp", model.ImageTemp + extension);
                var directory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "Member", CurrentUser.Id.Shrink());
                var largePath = Path.Combine(directory, model.ImageTemp + "-large" + extension);
                var normalPath = Path.Combine(directory, model.ImageTemp + extension);
                var microPath = Path.Combine(directory, model.ImageTemp + "-micro" + extension);

                using (Bitmap bitmap = new Bitmap(path))
                using (MemoryStream ms = new MemoryStream())
                {
                    bitmap.Save(ms, ImageFormat.Jpeg);
                    ms.Flush();
                    bitmap.Dispose();

                    var buff = Util.Image.Cut(ms.GetBuffer(), x1, y1, w, h);
                    ms.Dispose();

                    Util.Image.Save(buff, normalPath);
                    var large = Util.Image.Resize(buff, 300, 300);
                    Util.Image.Save(large, largePath);
                    var micro = Util.Image.Resize(buff, 100, 100);
                    Util.Image.Save(micro, microPath);
                }

                using (var uow = UnitOfWork.Begin())
                {
                    var member = MemberRepository.Get(CurrentUser.Id);
                    member.Portrait = model.ImageTemp;
                    uow.Commit();
                }

                if (Directory.Exists(path))
                {
                    Directory.Delete(path);
                }

                return this.RedirectToAction(r => r.Portrait());
            }
            else
            {
                var file = Request.Files[0];
                var fileId = Guid.NewGuid().Shrink();
                var fileName = fileId + ".jpg";
                var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "Temp", fileName);

                if (Directory.Exists(path))
                {
                    Directory.Delete(path);
                }

                Directory.CreateDirectory(Path.GetDirectoryName(path));

                file.SaveAs(path);

                model.ImageTemp = fileId;
                model.Id = model.Id;

                return View(model);
            }
        }

        [Authorization]
        [Authentication]
        public ActionResult Criterion()
        {
            var model = new CriterionModel();
            var member = MemberRepository.Get(CurrentUser.Id);
            if (member.Criterion != null)
            {
                var criteria = member.Criterion;
                model = new CriterionModel()
                {
                    AgeMin = criteria.AgeMin.ToString(),
                    AgeMax = criteria.AgeMax.ToString(),
                    HeightMin = criteria.HeightMin.ToString(),
                    HeightMax = criteria.HeightMax.ToString(),
                    Province = criteria.Province,
                    City = criteria.City,
                    Comment = criteria.Comment,
                    Education = criteria.Education,
                    EducationOver = criteria.EducationOver,
                    Grade = criteria.Grade,
                    Photograph = criteria.Photograph,
                    Marry = criteria.Marry
                };
            }

            ViewBag.AgeMinSet = WebUtil.GetRange(18, 65, 25, true, "不限");
            ViewBag.AgeMaxSet = WebUtil.GetRange(18, 65, 35, true, "不限");
            ViewBag.HeightMinSet = WebUtil.GetRange(140, 230, 160, true, "不限");
            ViewBag.HeightMaxSet = WebUtil.GetRange(140, 230, 180, true, "不限");
            ViewBag.EducationSet = DictionaryRepository.FindByType("education").ToSelectList(true, "不限");
            ViewBag.MarrySet = DictionaryRepository.FindByType("marry").ToSelectList(true, "不限");

            return View(model);
        }

        [Authorization]
        [Authentication]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Criterion(CriterionModel model)
        {
            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var member = MemberRepository.Get(CurrentUser.Id);
                    if (member.Criterion == null)
                    {
                        member.Criterion = new Criterion()
                        {
                            Member = member
                        };
                    }
                    var criteria = member.Criterion;
                    criteria.AgeMin = model.AgeMin != null ? (int?)int.Parse(model.AgeMin) : null;
                    criteria.AgeMax = model.AgeMax != null ? (int?)int.Parse(model.AgeMax) : null;
                    criteria.HeightMin = model.HeightMin != null ? (int?)int.Parse(model.HeightMin) : null;
                    criteria.HeightMax = model.HeightMax != null ? (int?)int.Parse(model.HeightMax) : null;
                    criteria.Province = model.Province;
                    criteria.City = model.City;
                    criteria.Comment = model.Comment;
                    criteria.Education = model.Education;
                    criteria.EducationOver = model.EducationOver;
                    criteria.Grade = model.Grade;
                    criteria.Marry = model.Marry;
                    criteria.Photograph = model.Photograph;

                    uow.Commit();
                }
            }
            return Criterion();
        }

        [Authorization]
        [Authentication]
        public ActionResult Identity()
        {
            var member = MemberRepository.Get(CurrentUser.Id);

            if (member.Realname.IsEmpty() || member.IdCard.IsEmpty())
            {
                return this.RedirectToAction(r => r.Identify());
            }

            var idCard = string.Empty;
            if (member.IdCard.Length == 15)
            {
                idCard = member.IdCard.Replace(member.IdCard.Substring(12, 3), "***");
            }
            else if (member.IdCard.Length == 18)
            {
                idCard = member.IdCard.Replace(member.IdCard.Substring(14, 4), "****");
            }

            var model = new IdentityModel
            {
                IdCard = idCard,
                IdCardType = member.IdCardType,
                Realname = member.Realname
            };
            return View(model);
        }

        [Authorization]
        public ActionResult Identify()
        {
            var member = MemberRepository.Get(CurrentUser.Id);
            var model = new IdentityModel
            {
                IdCard = member.IdCard,
                IdCardType = member.IdCardType,
                Realname = member.Realname
            };

            ViewBag.IdCardTypeSet = DictionaryRepository.FindByType("idCardType").ToSelectList(true);

            return View(model);
        }

        [Authorization]
        [Authentication]
        [ValidateAntiForgeryToken]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Identify(IdentityModel model)
        {
            var members = MemberRepository.Find(Spec<Member>.Eval(r => r.IdCard == model.IdCard)).ToList();

            if (members.Count > 0)
            {
                ModelState.AddModelError("", "证件号码已存在");
            }

            var regex = new Regex(@"^[0-9]{6}([0-9]{9}|[0-9]{11}([0-9]|x|X))$");
            if (model.IdCardType == "X" && !regex.IsMatch(model.IdCard))
            {
                ModelState.AddModelError("", "证件号码格式不正确");
            }

            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var member = MemberRepository.Get(CurrentUser.Id);

                    member.IdCard = model.IdCard;
                    member.IdCardType = model.IdCardType;
                    member.Realname = model.Realname;

                    uow.Commit();
                }
            }

            return Identify();
        }

        [Authorization]
        public ActionResult IdCardValidate(IdentityModel model)
        {
            var members = MemberRepository.Find(Spec<Member>.Eval(r => r.IdCard == model.IdCard)).ToList();

            if (members.Count > 0)
            {
                return Json(false, JsonRequestBehavior.AllowGet);
            }

            var regex = new Regex(@"^[0-9]{6}([0-9]{9}|[0-9]{11}([0-9]|x|X))$");
            return Json(model.IdCardType != "X" || regex.IsMatch(model.IdCard), JsonRequestBehavior.AllowGet);
        }

        [Authorization]
        public ActionResult Photograph()
        {
            var photos = MemberRepository.Get(CurrentUser.Id).DefaultAlbum.Photographs.Select(r =>
                new PhotographModel
                {
                    Caption = r.Caption,
                    Url = r.Url,
                }).ToList();

            var model = new AlbumModel
            {
                Id = CurrentUser.Id.Shrink(),
                Photos = photos
            };

            return View(model);
        }

        [Authorization]
        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult UploadPhotograph()
        {
            return View();
        }

        [Authorization]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult UploadPhotograph(PhotographModel model)
        {
            var extension = ".jpg";
            var file = Request.Files[0];
            var directory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "Member", CurrentUser.Id.Shrink());
            var fileId = Guid.NewGuid().Shrink();
            var fullPath = Path.Combine(directory, fileId + extension);
            var thumbnailPath = Path.Combine(directory, fileId + "-thumbnail" + extension);

            using (var bitmap = Bitmap.FromStream(file.InputStream))
            using (var ms = new MemoryStream())
            {
                bitmap.Save(ms, ImageFormat.Jpeg);
                ms.Flush();
                bitmap.Dispose();

                var buff = ms.GetBuffer();
                ms.Dispose();

                var thumbnail = Util.Image.Square(Util.Image.Fill(buff, 100), 100);
                Util.Image.Save(buff, fullPath);
                Util.Image.Save(thumbnail, thumbnailPath);
            }

            using (var uow = UnitOfWork.Begin())
            {
                var member = MemberRepository.Get(CurrentUser.Id);
                if (member.DefaultAlbum == null)
                {
                    member.EnsureDefaultAlbum();
                }

                member.DefaultAlbum.Photographs.Add(new Photograph()
                {
                    Id = Guid.NewGuid(),
                    CreateAt = DateTime.Now,
                    Caption = model.Caption,
                    Url = fileId,
                    Audit = Audit.None
                });

                uow.Commit();
            }

            return this.RedirectToAction(r => r.Photograph());
        }

        [Authorization]
        public ActionResult Mobile()
        {
            var member = MemberRepository.Get(CurrentUser.Id);

            if (member.MobileVerified == false)
            {
                return this.RedirectToAction(r => r.VerifyMobile());
            }

            var viewModel = new MobileModel
            {
                Mobile = member.Mobile,
                MobileVerified = member.MobileVerified
            };

            return View(viewModel);
        }

        [Authorization]
        [Authentication]
        public ActionResult VerifyMobile()
        {
            return View();
        }

        [Authorization]
        [Authentication]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult VerifyMobile(MobileModel model, string returnUrl)
        {
            var user = UserRepository.Get(CurrentUser.Id);

            var proof = user.LatestProof;

            if (proof == null)
            {
                ModelState.AddModelError("", "验证码错误。");
            }
            else
            {
                if (proof.IsExpired())
                {
                    ModelState.AddModelError("", "验证码已过期。");
                }
                if (proof.Mobile.Equals(model.Mobile) == false)
                {
                    ModelState.AddModelError("", "手机号码不匹配。");
                }
                if (proof.Value.Equals(model.VerificationCode) == false)
                {
                    ModelState.AddModelError("", "验证码错误。");
                }
            }

            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    proof.Used = true;
                    proof.User.Member.Mobile = proof.Mobile;
                    proof.User.Member.MobileVerified = true;

                    uow.Commit();
                }

                if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                            && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                {
                    return Redirect(returnUrl);
                }
                else
                {
                    return this.RedirectToAction(r => r.Mobile());
                }
            }

            return View();
        }

        [Authorization]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult VerifyCode(string mobile)
        {
            var user = UserRepository.Get(CurrentUser.Id);

            if (user.CanSendTextMessage() == false)
            {
                ModelState.AddModelError("", Resources.Error_4002_Max_Text_Message);
            }

            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var proof = new Proof
                    {
                        Id = Guid.NewGuid(),
                        CreateAt = DateTime.Now,
                        User = user,
                        Value = Util.GetRandomProof(),
                        Mobile = mobile,
                    };

                    user.Proofs.Add(proof);

                    uow.Commit();

                    EventAggregator.GetEvent<MobileVerificationEvent>().Publish(new MobileVerificationEventArgs(proof));
                }

                return Json(true);
            }
            else
            {
                return Json(ModelState.Values.Select(r => r.Errors.Select(q => q.ErrorMessage)));
            }
        }

        [Authorization]
        public ActionResult Email()
        {
            var user = UserRepository.Get(CurrentUser.Id);

            if (user.EmailVerified == false)
            {
                return this.RedirectToAction(r => r.VerifyEmail());
            }

            var viewModel = new EmailModel
            {
                Email = user.Email,
                EmailVerified = user.EmailVerified
            };

            return View(viewModel);
        }

        [Authorization]
        [Authentication]
        public ActionResult VerifyEmail()
        {
            var user = UserRepository.Get(CurrentUser.Id);

            var viewModel = new EmailModel
            {
                EmailVerified = user.EmailVerified,
            };

            return View(viewModel);
        }

        [Authorization]
        [Authentication]
        [ValidateAntiForgeryToken]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult VerifyEmail(EmailModel model)
        {
            var user = UserRepository.Get(CurrentUser.Id);

            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var token = Guid.NewGuid();

                    var proof = new Proof
                    {
                        Id = Guid.NewGuid(),
                        CreateAt = DateTime.Now,
                        Email = model.NewEmail,
                        User = user,
                        Value = Convert.ToBase64String(token.ToByteArray()),
                    };

                    user.Proofs.Add(proof);

                    uow.Commit();

                    EventAggregator.GetEvent<EmailVerificationEvent>().Publish(new EmailVerificationEventArgs(user, proof.Email, token));
                }

                return this.RedirectToAction(r => r.SendEmailVerificationSuccess(model.NewEmail));
            }

            var viewModel = new EmailModel
            {
                EmailVerified = user.EmailVerified,
            };

            return View(viewModel);
        }

        public ActionResult ActivateEmail(string token)
        {
            var proof = UserRepository.GetProof(token.ToGuid());
            if (proof == null)
            {
                ModelState.AddModelError("", Resources.Error_1000_Unknow_Error);
            }
            else
            {
                if (DateTime.Now > proof.CreateAt.AddDays(1))
                {
                    ModelState.AddModelError("", Resources.Error_4003_Token_Expiry);
                }
            }

            if (ModelState.IsValid)
            {
                using (var uow = UnitOfWork.Begin())
                {
                    proof.Used = true;
                    proof.User.Email = proof.Email;
                    proof.User.EmailVerified = true;

                    uow.Commit();
                }

                return this.RedirectToAction(r => r.VerifyEmail());
            }

            return View();
        }

        public ActionResult SendEmailVerificationSuccess(string email)
        {
            var viewModel = new EmailModel
            {
                NewEmail = email,
            };

            return View(viewModel);
        }

    }
}
